import { Link, Contribution } from '@brillout/docpress'
import { UiFrameworkExtension, Advanced } from '../../components'

> **What is a store?**
>
> A store (aka state management) is a tool that helps you manage complex UI state.
>
> Not properly managing UI state is one of the most common causes of buggy user interfaces. A store enables you to get even the most complex UI state logic under control.
>
> A store works by representing state changes as atomic changes to an immutable data structure, enabling a fundamentally more robust state management.

We recommend using <Link href="/extensions">Vike extensions</Link> for automatically integrating state management tools.

**React**

- [`vike-react-redux`](https://github.com/vikejs/vike-react/tree/main/packages/vike-react-redux#readme)
- [`vike-react-zustand`](https://github.com/vikejs/vike-react/tree/main/packages/vike-react-zustand#readme)

**Vue**

- [`vike-vue-pinia`](https://github.com/vikejs/vike-vue/tree/main/packages/vike-vue-pinia#readme)

<Contribution>
Contribution welcome to [create Vike extensions](https://github.com/vikejs/vike/issues/1715) integrating stores with SSR.
</Contribution>

You can also manually integrate any state management tool you want.


## Manual integration

<Advanced>
  Instead of manually integrating your store, we generally recommend using a <Link href="/extensions">Vike extension</Link> instead.
</Advanced>

> <Link href="/faq#how-can-i-reach-out-for-help">Feel free to reach out</Link> if you want help integrating a store.

{/* Similar text at https://vike.dev/integration#data-fetching */ }

When using a store with SSR, the initial state of the store is determined on the server side (during SSR) and then passed to the client side.

You must ensure that the store's initial state is exactly the same on both the client- and the server-side (otherwise, you'll get a <Link href="/hydration-mismatch">hydration mismatch</Link>).

The integration can be broken down into three steps:

**1. SSR**

Determine the store's initial state on the server-side (during SSR) and <Link href="/pageContext#custom">make it available as `pageContext.storeInitialState`</Link>.

To achieve that, you can create the store at <Link href="/onCreatePageContext">`+onCreatePageContext.server.js`</Link>  and then retrieve its initial sate at <Link href="/onAfterRenderHtml">`+onAfterRenderHtml.js`</Link>:
```ts
// pages/+onCreatePageContext.server.ts
// Environment: server

import type { PageContextServer } from 'vike/types'
import { createStore } from 'awesome-store'

export function onCreatePageContext(pageContext: PageContextServer) {
  pageContext.store = createStore()
}
```
```ts
// pages/+onAfterRenderHtml.ts
// Environment: server

import type { PageContextServer } from 'vike/types'

export function onAfterRenderHtml(pageContext: PageContextServer) {
  pageContext.storeInitialState = pageContext.store.getState()
}
```

> **If you use React or Solid**, you may need to use <Link href="/Wrapper">`+Wrapper`</Link>:
> ```tsx
> // pages/+Wrapper.tsx
> // Environment: server, client
>
> import React from 'react'
> import { Provider } from 'awesome-store/react'
> import { usePageContext } from 'vike-react/usePageContext'
>
> export default function StoreProvider({ children }: { children: React.ReactNode }) {
>   const pageContext = usePageContext()
>   return <Provider store={pageContext.store}>{children}</Provider>
> }
> ```

> **If you use Vue**, you may need to use <Link href="/onCreateApp">`+onCreateApp`</Link>:
> ```ts
> // pages/+onCreateApp.ts
> // Environment: server & client
>
> export { onCreateApp }
>
> import StoreVuePlugin from 'awesome-store/vue-plugin'
> import type { PageContext } from 'vike/types'
>
> function onCreateApp(pageContext: PageContext) {
>   if (pageContext.isRenderingHead) {
>     // Don't add plugins when rendering <head> — see https://vike.dev/onCreateApp#lifecycle
>     return
>   }
>   const app = pageContext.app!
>   app.use(StoreVuePlugin)
> }
> ```

**2. `passToClient`**

Make `pageContext.storeInitialState` available on the client-side by using <Link href="/passToClient">`passToClient`</Link>:
```ts
// pages/+config.ts

import type { Config } from 'vike/types'

export default {
  passToClient: ['storeInitialState']
} satisfies Config
```

**3. Hydration**

On the client-side, initialize the store with `pageContext.storeInitialState` upon hydration, for example at <Link href="/onBeforeRenderClient">`+onBeforeRenderClient`</Link>:
```ts
// pages/+onBeforeRenderClient.ts
// Environment: client

import type { PageContextClient } from 'vike/types'
import { createStore } from 'awesome-store'

export function onBeforeRenderClient(pageContext: PageContextClient) {
  if (pageContext.isHydration) {
    // Hydration. We must use the same state than on the server-side.
    pageContext.globalContext.store = createStore(pageContext.storeInitialState)
  } else {
    // Client-side navigation. Nothing to do: the store was already initialized at hydration.
    assert(pageContext.globalContext.store)
  }
}
```

> To create the store earlier you can use <Link href="/onCreateGlobalContext">`+onCreateGlobalContext.client.js`</Link> instead.

> See also:
> - <Link href="/pageContext#isHydration">API > `pageContext.isHydration`</Link>
> - <Link href="/pageContext#globalContext">API > `pageContext.globalContext`</Link>


## See also

- <Link href="/redux" />
- <Link href="/pinia" />
- <Link href="/tools#stores" />
